home *** CD-ROM | disk | FTP | other *** search
/ PC Format (PL) 2008 February / PC_Format_022008.iso / Internet / Mozilla Thunderbird wtyczki / lightning-0.7-tb-win.xpi / chrome / lightning.jar / content / lightning / imip-bar.js < prev    next >
Encoding:
JavaScript  |  2007-09-28  |  15.0 KB  |  404 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is Lightning code.
  16.  *
  17.  * The Initial Developer of the Original Code is Simdesk Technologies Inc.
  18.  * Portions created by the Initial Developer are Copyright (C) 2006
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Clint Talbert <ctalbert.moz@gmail.com>
  23.  *   Matthew Willis <lilmatt@mozilla.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or 
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /**
  40.  * This bar lives inside the message window.
  41.  * Its lifetime is the lifetime of the main thunderbird message window.
  42.  */
  43.  
  44. var gItipItem;
  45.  
  46. const onItipItem = {
  47.     observe: function observe(subject, topic, state) {
  48.         if (topic == "onItipItemCreation") {
  49.             checkForItipItem(subject);
  50.         }
  51.     }
  52. };
  53.  
  54. function checkForItipItem(subject)
  55. {
  56.     var itipItem;
  57.     try {
  58.         if (!subject) {
  59.             var msgUri = GetLoadedMessage();
  60.             var sinkProps = msgWindow.msgHeaderSink.properties;
  61.             // This property was set by LightningTextCalendarConverter.js
  62.             itipItem = sinkProps.getPropertyAsInterface("itipItem",
  63.                                                         Components.interfaces.calIItipItem);
  64.         } else {
  65.             // With Thunderbird 1.5.x we have to use the subject to pass the
  66.             // iTIP item because we don't have sinkProps available.
  67.             itipItem = subject.QueryInterface(Components.interfaces.calIItipItem);
  68.         }
  69.     } catch (e) {
  70.         // This will throw on every message viewed that doesn't have the
  71.         // itipItem property set on it. So we eat the errors and move on.
  72.  
  73.         // XXX TODO: Only swallow the errors we need to. Throw all others.
  74.         return;
  75.     }
  76.  
  77.     // We are only called upon receipt of an invite, so ensure that isSend
  78.     // is false.
  79.     itipItem.isSend = false;
  80.  
  81.     // XXX Get these from preferences
  82.     itipItem.autoResponse = Components.interfaces.calIItipItem.USER;
  83.  
  84.     var imipMethod = getMsgImipMethod();
  85.     if (imipMethod &&
  86.         imipMethod.length != 0 &&
  87.         imipMethod.toLowerCase() != "nomethod")
  88.     {
  89.         itipItem.receivedMethod = imipMethod;
  90.     } else {
  91.         // There is no METHOD in the content-type header (spec violation).
  92.         // Fall back to using the one from the itipItem's ICS.
  93.         imipMethod = itipItem.receivedMethod;
  94.     }
  95.  
  96.     gItipItem = itipItem;
  97.  
  98.     // XXX Bug 351742: no S/MIME or spoofing protection yet
  99.     // handleImipSecurity(imipMethod);
  100.  
  101.     setupBar(imipMethod);
  102. }
  103.  
  104. addEventListener("messagepane-loaded", imipOnLoad, true);
  105. addEventListener("messagepane-unloaded", imipOnUnload, true);
  106.  
  107. /**
  108.  * Add self to gMessageListeners defined in msgHdrViewOverlay.js
  109.  */
  110. function imipOnLoad()
  111. {
  112.     var listener = {};
  113.     listener.onStartHeaders = onImipStartHeaders;
  114.     listener.onEndHeaders = onImipEndHeaders;
  115.     gMessageListeners.push(listener);
  116.  
  117.     // Set up our observers
  118.     var observerSvc = Components.classes["@mozilla.org/observer-service;1"]
  119.                                 .getService(Components.interfaces.nsIObserverService);
  120.     observerSvc.addObserver(onItipItem, "onItipItemCreation", false);
  121. }
  122.  
  123. function imipOnUnload()
  124. {
  125.     removeEventListener("messagepane-loaded", imipOnLoad, true);
  126.     removeEventListener("messagepane-unloaded", imipOnUnload, true);
  127.  
  128.     var observerSvc = Components.classes["@mozilla.org/observer-service;1"]
  129.                                 .getService(Components.interfaces.nsIObserverService);
  130.     observerSvc.removeObserver(onItipItem, "onItipItemCreation");
  131.  
  132.     gItipItem = null;
  133. }
  134.  
  135. function onImipStartHeaders()
  136. {
  137.     var imipBar = document.getElementById("imip-bar");
  138.     imipBar.setAttribute("collapsed", "true");
  139.     document.getElementById("imip-button1").setAttribute("hidden", "true");
  140.     document.getElementById("imip-button2").setAttribute("hidden", "true");
  141.  
  142.     // A new message is starting.
  143.     // Clear our iMIP/iTIP stuff so it doesn't contain stale information.
  144.     imipMethod = "";
  145.     gItipItem = null;
  146. }
  147.  
  148. /**
  149.  * Required by MessageListener. no-op
  150.  */
  151. function onImipEndHeaders()
  152. {
  153.     // no-op
  154. }
  155.  
  156. function setupBar(imipMethod)
  157. {
  158.     // XXX - Bug 348666 - Currently we only do REQUEST requests
  159.     // In the future this function will set up the proper actions
  160.     // and attributes for the buttons as based on the iMIP Method
  161.     var imipBar = document.getElementById("imip-bar");
  162.     imipBar.setAttribute("collapsed", "false");
  163.     var description = document.getElementById("imip-description");
  164.  
  165.     // Bug 348666: here is where we would check if this event was already
  166.     // added to calendar or not and display correct information
  167.  
  168.     if (imipMethod.toUpperCase() == "REQUEST") {
  169.         if (description.firstChild.data) {
  170.             description.firstChild.data = ltnGetString("lightning",
  171.                                                        "imipBarRequestText");
  172.         }
  173.  
  174.         var button = document.getElementById("imip-button1");
  175.         button.removeAttribute("hidden");
  176.         button.setAttribute("label", ltnGetString("lightning",
  177.                                                   "imipAcceptInvitation.label"));
  178.         button.setAttribute("oncommand",
  179.                             "setAttendeeResponse('ACCEPTED', 'CONFIRMED');");
  180.  
  181.         // Create a DECLINE button
  182.         button = document.getElementById("imip-button2");
  183.         button.removeAttribute("hidden");
  184.         button.setAttribute("label", ltnGetString("lightning",
  185.                                                   "imipDeclineInvitation.label"));
  186.         button.setAttribute("oncommand",
  187.                             "setAttendeeResponse('DECLINED', 'CONFIRMED');");
  188.     } else if (imipMethod.toUpperCase() == "REPLY") {
  189.         // Bug xxxx we currently cannot process REPLY messages so just let
  190.         // the user know what this is, and don't give them any options.
  191.         if (description.firstChild.data) {
  192.             description.firstChild.data = ltnGetString("lightning",
  193.                                                        "imipBarReplyText");
  194.         }
  195.     } else if (imipMethod.toUpperCase() == "PUBLISH") {
  196.         if (description.firstChild.data) {
  197.             description.firstChild.data = ltnGetString("lightning",
  198.                                                        "imipBarRequestText");
  199.         }
  200.  
  201.         var button = document.getElementById("imip-button1");
  202.         button.removeAttribute("hidden");
  203.         button.setAttribute("label", ltnGetString("lightning",
  204.                                                   "imipAddToCalendar.label"));
  205.         
  206.         button.setAttribute("oncommand",
  207.                             "setAttendeeResponse('PUBLISH', '');");
  208.     } else {
  209.         // Bug xxxx TBD: Something went wrong or we found a message we don't
  210.         // support yet. We can show a "This method is not supported in this
  211.         // version" or simply hide the iMIP bar at this point
  212.         if (description.firstChild.data) {
  213.             description.firstChild.data = ltnGetString("lightning",
  214.                                                        "imipBarUnsupportedText");
  215.         }
  216.         Components.utils.reportError("Unknown imipMethod: " + imipMethod);
  217.     }
  218. }
  219.  
  220. function getMsgImipMethod()
  221. {
  222.     var imipMethod = "";
  223.     var msgURI = GetLoadedMessage();
  224.     var msgHdr = messenger.messageServiceFromURI(msgURI)
  225.                           .messageURIToMsgHdr(msgURI);
  226.     imipMethod = msgHdr.getStringProperty("imip_method");
  227.     return imipMethod;
  228. }
  229.  
  230. function getMsgRecipient()
  231. {
  232.     var imipRecipient = "";
  233.     var msgURI = GetLoadedMessage();
  234.     var msgHdr = messenger.messageServiceFromURI(msgURI)
  235.                           .messageURIToMsgHdr(msgURI);
  236.  
  237.     // msgHdr recipients can be a comma separated list of recipients.
  238.     // We then compare against the defaultIdentity to find ourselves.
  239.     // XXX This won't always work:
  240.     //     Users with multiple accounts and invites going to the non-default
  241.     //     account, Users with email aliases where the defaultIdentity.email
  242.     //     doesn't match the recipient, etc.
  243.     if (msgHdr) {
  244.         var recipientList = msgHdr.recipients;
  245.         // Remove any spaces
  246.         recipientList = recipientList.split(" ").join("");
  247.         recipientList = recipientList.split(",");
  248.  
  249.         var emailSvc = Components.classes["@mozilla.org/calendar/itip-transport;1?type=email"]
  250.                                  .getService(Components.interfaces.calIItipTransport);
  251.         var me = emailSvc.defaultIdentity;
  252.  
  253.         var lt;
  254.         var gt;
  255.         for each (var recipient in recipientList) {
  256.             // Deal with <foo@bar.com> style addresses
  257.             lt = recipient.indexOf("<");
  258.             gt = recipient.indexOf(">");
  259.  
  260.             // I chose 6 since <a@b.c> is the shortest technically valid email
  261.             // address I could come up with.
  262.             if ((lt >= 0) && (gt >= 6)) {
  263.                 recipient = recipient.substring(lt+1, gt);
  264.             }
  265.  
  266.             if (recipient.toLowerCase() == me.toLowerCase()) {
  267.                 imipRecipient = recipient;
  268.             }
  269.         }
  270.     }
  271.     return imipRecipient;
  272. }
  273.  
  274. /**
  275.  * Call the calendar picker
  276.  */
  277. function getTargetCalendar()
  278. {
  279.     var calendarToReturn;
  280.     var calMgr = Components.classes["@mozilla.org/calendar/manager;1"]
  281.                            .getService(Components.interfaces.calICalendarManager);
  282.     var count = new Object();
  283.     var calArray = calMgr.getCalendars(count);
  284.  
  285.     if (count.value == 1) {
  286.         // There's only one calendar, so it's silly to ask what calendar
  287.         // the user wants to import into.
  288.         calendarToReturn = calArray[0];
  289.     } else {
  290.         // Ask what calendar to import into
  291.         var args = new Object();
  292.         var aCal;
  293.         args.onOk = function selectCalendar(aCal) { calendarToReturn = aCal; };
  294.         args.promptText = calGetString("calendar", "importPrompt");
  295.         openDialog("chrome://calendar/content/chooseCalendarDialog.xul",
  296.                    "_blank", "chrome,titlebar,modal,resizable", args);
  297.     }
  298.     return calendarToReturn;
  299. }
  300.  
  301. /**
  302.  * Type is type of response
  303.  * event_status is an optional directive to set the Event STATUS property
  304.  */
  305. function setAttendeeResponse(type, eventStatus)
  306. {
  307.     var myAddress = getMsgRecipient();
  308.     if (type && gItipItem) {
  309.         // We set the attendee status appropriately
  310.         switch (type) {
  311.             case "ACCEPTED":
  312.             case "TENTATIVE":
  313.             case "DECLINED":
  314.                 gItipItem.setAttendeeStatus(myAddress, type);
  315.                 // fall through
  316.             case "REPLY":
  317.             case "PUBLISH":
  318.                 doResponse(eventStatus);
  319.                 break;
  320.             default:
  321.                 // no-op. The attendee wishes to disregard the mail, so no
  322.                 // further action is required.
  323.                 break;
  324.         }
  325.     }
  326. }
  327.  
  328. /**
  329.  * doResponse performs the iTIP action for the current ItipItem that we
  330.  * parsed from the email.
  331.  * @param  aLocalStatus  optional parameter to set the event STATUS property.
  332.  *         aLocalStatus can be empty, "TENTATIVE", "CONFIRMED", or "CANCELLED"
  333.  */
  334. function doResponse(aLocalStatus)
  335. {
  336.     // calIOperationListener so that we can properly return status to the
  337.     // imip-bar
  338.     var operationListener = {
  339.         onOperationComplete:
  340.         function ooc(aCalendar, aStatus, aOperationType, aId, aDetail) {
  341.             // Call finishItipAction to set the status of the operation
  342.             finishItipAction(aOperationType, aStatus, aDetail);
  343.         },
  344.  
  345.         onGetResult:
  346.         function ogr(aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
  347.             // no-op
  348.         }
  349.     };
  350.  
  351.     // The spec is unclear if we must add all the items or if the
  352.     // user should get to pick which item gets added.
  353.     var targetCalendar = getTargetCalendar();
  354.     gItipItem.targetCalendar = targetCalendar;
  355.  
  356.     if (aLocalStatus != null) {
  357.         gItipItem.localStatus = aLocalStatus;
  358.     }
  359.  
  360.     var itipProc = Components.classes["@mozilla.org/calendar/itip-processor;1"]
  361.                              .createInstance(Components.interfaces.calIItipProcessor);
  362.  
  363.     itipProc.processItipItem(gItipItem, operationListener);
  364. }
  365.  
  366. /**
  367.  * Bug 348666 (complete iTIP support) - This gives the user an indication
  368.  * that the Action occurred.
  369.  *
  370.  * In the future, this will store the status of the invitation in the
  371.  * invitation manager.  This will enable us to provide the ability to request
  372.  * updates from the organizer and to suggest changes to invitations.
  373.  *
  374.  * Currently, this is called from our calIOperationListener that is sent to
  375.  * the ItipProcessor. This conveys the status of the local iTIP processing
  376.  * on your calendar. It does not convey the success or failure of sending a
  377.  * response to the ItipItem.
  378.  */
  379. function finishItipAction(aOperationType, aStatus, aDetail)
  380. {
  381.     // For now, we just state the status for the user something very simple
  382.     var desc = document.getElementById("imip-description");
  383.     if (desc.firstChild != null) {
  384.         if (Components.isSuccessCode(aStatus)) {
  385.             desc.firstChild.data = ltnGetString("lightning",
  386.                                                 "imipAddedItemToCal");
  387.             document.getElementById("imip-button1").setAttribute("hidden",
  388.                                                                  true);
  389.             document.getElementById("imip-button2").setAttribute("hidden",
  390.                                                                  true);
  391.         } else {
  392.             // Bug 348666: When we handle more iTIP methods, we need to create
  393.             // more sophisticated error handling.
  394.             document.getElementById("imip-bar").setAttribute("collapsed", true);
  395.             var msg = "Invitation could not be processed. Status: " + aStatus;
  396.             if (aDetail) {
  397.                 msg += "\nDetails: " + aDetail;
  398.             }
  399.             // Defined in import-export
  400.             showError(msg);
  401.         }
  402.     }
  403. }
  404.